/*
 * Created on 2006-7-8
 */
package field;

import java.util.*;

/**
 * 
 * This class provides a wrap of the <Double, ArrayList> map where the arraylist
 * stores the object ids who have the distance.
 * 
 * @author g0404403
 * @email wuw@nus.edu.sg
 */
public class DisObjsMap {

	TreeMap<Double, HashSet<Integer>> disObjsMap;

	public DisObjsMap() {
		this.disObjsMap = new TreeMap<Double, HashSet<Integer>>();
	}

	public void put(double dis, int oid) {
		if (this.disObjsMap.containsKey(dis)) {
			this.disObjsMap.get(dis).add(oid);
		} else {
			HashSet<Integer> oids = new HashSet<Integer>();
			oids.add(oid);
			this.disObjsMap.put(dis, oids);
		}
	}

	/**
	 * @param k
	 *            This will keep the objects whose distances is no larger than
	 *            the kth distance. Objects whose distances equal to the kth
	 *            will be kept. Others will be deleted.
	 */
	public void retainK(int k) {
		int numResult = 0;
		HashSet<Double> toDelete = new HashSet<Double>();
		for (Double dis : this.disObjsMap.keySet()) {
			if (numResult < k) {
				HashSet<Integer> al_oids = this.disObjsMap.get(dis);
				numResult = numResult + al_oids.size();
			} else {
				toDelete.add(dis);
			}
		}
		for (Double dis : toDelete) {
			this.disObjsMap.remove(dis);
		}
	}

	public boolean containsKey(Double key) {
		return this.disObjsMap.containsKey(key);
	}

	public double lastKey() {
		Double lastkey = (Double) this.disObjsMap.lastKey();
		return lastkey.doubleValue();
	}

	/**
	 * @param k
	 * @return the kth distance
	 */
	public int critical(int k) {
		this.retainK(k);
		Double lastkey = (Double) this.disObjsMap.lastKey();
		HashSet<Integer> oids = this.disObjsMap.get(lastkey);
		assert oids.size() > 0 : "there is no object in the set";
		int coid = -1;
		for (Integer oid : oids) {
			coid = oid;
		}
		return coid;
	}

	public HashSet<Integer> topKOids(int k) {
		assert (this.size() >= k) : "in topKOids, size less than k";
		HashSet<Integer> oids = new HashSet<Integer>();
		for (Double key : this.disObjsMap.keySet()) {
			HashSet<Integer> al_oids = this.disObjsMap.get(key);
			for (int oid : al_oids) {
				if (oids.size() < k) {
					oids.add(oid);
				}
			}
		}
		return oids;
	}

	public int size() {
		int count = 0;
		for (Double key : this.disObjsMap.keySet()) {
			count = count + this.disObjsMap.get(key).size();
		}
		return count;
	}

	public String toString() {
		return this.disObjsMap.toString();
	}

}
